package com.caipos.actor.tenant;

import com.caipos.actor.ActorSystemContext;
import com.caipos.actor.common.actors.*;
import com.caipos.actor.common.data.EntityType;
import com.caipos.actor.common.data.Tenant;
import com.caipos.actor.common.data.id.DeviceId;
import com.caipos.actor.common.data.id.TenantId;
import com.caipos.actor.common.data.id.TenantProfileId;
import com.caipos.actor.common.msg.KbActorMsg;
import com.caipos.actor.common.msg.KbActorStopReason;
import com.caipos.actor.ruleChain.RuleChainManagerActor;
import com.caipos.actor.device.DeviceActorCreator;
import com.caipos.actor.service.ContextBasedCreator;
import com.caipos.actor.service.DefaultActorService;
import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Slf4j
public class TenantActor extends RuleChainManagerActor {

    private boolean isRuleEngine;
    private boolean isCore;

    private Set<DeviceId> deletedDevices;

    private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
        super(systemContext, tenantId);
        this.deletedDevices = new HashSet<>();
    }

    boolean cantFindTenant = false;

    @Override
    public void init(KbActorCtx ctx) throws KbActorException {
        super.init(ctx);
        log.debug("[{}] Starting tenant actor.", tenantId);
        try {
            Tenant tenant = systemContext.getTenantService().getTenantById(tenantId.getId());
            if (tenant == null) {
                cantFindTenant = true;
                log.info("[{}] Started tenant actor for missing tenant.", tenantId);
            } else {
                initRuleChains();
                log.debug("[{}] Tenant actor started.", tenantId);
            }
        } catch (Exception e) {
            log.warn("[{}] Unknown failure", tenantId, e);
        }

//        try {
//            Tenant tenant =Tenant.builder()
//                    .region("Global")
//                    .title("ScottXu")
//                    .version(1L)
//                    .tenantProfileId("eaa02c30-e8f2-11ef-bb55-753a9a0dab3b")
//                    .build();
////            systemContext.getTenantService().findTenantById(tenantId);
//            log.debug("[{}] Going to init rule chains", tenantId);
//            initRuleChains();
//        } catch (Exception e) {
//            log.warn("[{}] Unknown failure", tenantId, e);
//        }
    }

    @Override
    public void destroy(KbActorStopReason stopReason, Throwable cause) {
        log.info("[{}] Stopping tenant actor.", tenantId);
    }

    @Override
    protected boolean doProcess(KbActorMsg msg) {
        if (cantFindTenant) {
            return true;
        }
        switch (msg.getMsgType()) {
            case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
            case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
            case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
            case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG:
            case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
            case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
            case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
            case SESSION_TIMEOUT_MSG:
                ctx.broadcastToChildrenByType(msg, EntityType.DEVICE);
                break;
            case RULE_CHAIN_INPUT_MSG:
            case RULE_CHAIN_OUTPUT_MSG:
            default:
                return false;
        }
        return true;
    }

//    private void onRuleChainMsg(RuleChainAwareMsg msg) {
//        if (getApiUsageState().isReExecEnabled()) {
//            getOrCreateActor(msg.getRuleChainId()).tell(msg);
//        }
//    }
//
//    private void onToDeviceActorMsg(DeviceAwareMsg msg, boolean priority) {
//        KbActorRef deviceActor = getOrCreateDeviceActor(msg.getDeviceId());
//        if (priority) {
//            deviceActor.tellWithHighPriority(msg);
//        } else {
//            deviceActor.tell(msg);
//        }
//    }

    private KbActorRef getOrCreateDeviceActor(DeviceId deviceId) {
        return ctx.getOrCreateChildActor(new KbEntityActorId(deviceId),
                () -> DefaultActorService.DEVICE_DISPATCHER_NAME,
                () -> new DeviceActorCreator(systemContext, tenantId, deviceId),
                () -> true);
    }

    @Override
    public ProcessFailureStrategy onProcessFailure(KbActorMsg msg, Throwable t) {
        log.error("[{}] Failed to process msg: {}", tenantId, msg, t);
        return doProcessFailure(t);
    }

    public static class ActorCreator extends ContextBasedCreator {

        private final TenantId tenantId;

        public ActorCreator(ActorSystemContext context, TenantId tenantId) {
            super(context);
            this.tenantId = tenantId;
        }

        @Override
        public KbActorId createActorId() {
            return new KbEntityActorId(tenantId);
        }

        @Override
        public KbActor createActor() {
            return new TenantActor(context, tenantId);
        }
    }

}
